package com.zpself.module.多线程.Lock;

import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author By ZengPeng
 * @Description CountDownLatch是一个同步工具类，用来协调多个线程之间的同步，
 *               或者说起到线程之间的通信（而不是用作互斥的作用）。
 *
 *              CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后，再继续执行。
 *              使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后，计数器的值就会减一。
 *              当计数器的值为0时，表示所有的线程都已经完成一些任务，然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
 *
 *
 *  用法1： 等待多个任务线程执行完，当计数器的值变为0时 await的线程就会被唤醒，适用于主线程需要等待多个组件线程加载完！
 *  用法2： 多个线程同时执行，等待发令枪；将CountDownLatch(1),多线程加入等待，在将计数器置为0，线程同时被唤醒。
 * @date in  2021/2/22 14:53
 * @Modified By
 */
public class 分析CountDownLatch {

    @Test
    //用法1：等待多个任务线程执行完，当计数器的值变为0时 await的线程就会被唤醒，适用于主线程需要等待多个组件线程加载完！
    public void test() throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(3);
        CountDownLatch cal=new CountDownLatch(3);
        for (int i = 0; i < 3; i++) {
            pool.execute(new Runnable(){
                @Override
                public void run() {
                    try {
                        System.out.println("子线程" + Thread.currentThread().getName() + "开始执行");
                        Thread.sleep((long) (Math.random() * 5000));
                        System.out.println("子线程"+Thread.currentThread().getName()+"执行完成");
                        cal.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        System.out.println("主线程"+Thread.currentThread().getName()+"等待子线程执行完成...");
        cal.await();//阻塞当前线程，直到计数器的值为0
        System.out.println("主线程"+Thread.currentThread().getName()+"开始执行...");
    }


    @Test
    //用法2：多个线程同时执行，等待发令枪；将CountDownLatch(1),多线程加入等待，在将计数器置为0，线程同时被唤醒。
    public void test2() throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        final CountDownLatch cdOrder = new CountDownLatch(1);//选手等候命令
        final CountDownLatch cdAnswer = new CountDownLatch(4);//选手跑完了  ，统计结果
        for (int i = 0; i < 4; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("选手" + Thread.currentThread().getName() + "正在等待裁判发布口令");
                        cdOrder.await();
                        System.out.println("选手" + Thread.currentThread().getName() + "已接受裁判口令");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("选手" + Thread.currentThread().getName() + "到达终点");
                        cdAnswer.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }
        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("裁判"+Thread.currentThread().getName()+"即将发布口令");
            cdOrder.countDown();
            System.out.println("裁判"+Thread.currentThread().getName()+"已发送口令，正在等待所有选手到达终点");
            cdAnswer.await();
            System.out.println("所有选手都到达终点");
            System.out.println("裁判"+Thread.currentThread().getName()+"汇总成绩排名");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.shutdown();
    }
}
